/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.data.dao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.mapsforge.android.maps.GeoPoint;

import de.fuberlin.kosmik.data.DataBaseConnector;

/**
 * Data container for displaying a track.
 */
public class TrackData {

	/**
	 * Mapping from a way-id to a <code>List</code> of {@link GeoPoint}s which
	 * are part of a way of this track. This list in not implemented for
	 * concurrent access, change it only if you really know what you are doing,
	 * and only when this <code>TrackData</code> object has already been
	 * completely instantiated.
	 */
	public Map<Long, List<GeoPoint>> pointMap = new TreeMap<Long, List<GeoPoint>>();
	/**
	 * A convenience Map to save data-base accesses which stores whether a
	 * certain way is actually an area. In the data base level Areas are the
	 * same as Ways but with the boolean attribute <code>is_way</code> set to
	 * <code>true</code>
	 */
	public Map<Long, Boolean> wayIsAreaMap = new TreeMap<Long, Boolean>();

	private GeoPoint firstPoint = null;
	private DataBaseConnector db;
	private Collection<Poi> pois;
	private long trackId;
	private long noWayIndex = 1; // will start from noWayIndex-1
	private boolean lastPointWasWay = true;

	/**
	 * Constructor for the TrackData object. This call is not yet filling this
	 * object with any information. points must be entered through
	 * {@link #putPoint(double, double, long)}
	 * 
	 * @param trackId the database id of this track
	 * @param db DataBaseConnector instance from which necessary information
	 *            will be taken
	 */
	public TrackData(long trackId, DataBaseConnector db) {
		this.db = db;
		this.trackId = trackId;

	}

	/**
	 * Insert a point (longitude, latitude tuple) to a way.
	 * 
	 * @param lng longitude
	 * @param lat latitude
	 * @param wayId data base id of the way
	 */
	public void putPoint(double lng, double lat, long wayId) {

		boolean isWay = wayId != 0;

		GeoPoint point = new GeoPoint(lat, lng);

		if (firstPoint == null)
			firstPoint = point;

		if (isWay) {
			lastPointWasWay = true;
			if (pointMap.containsKey(Long.valueOf(wayId))) {

				pointMap.get(Long.valueOf(wayId)).add(point);

			} else {

				boolean isArea = isArea(wayId);

				List<GeoPoint> points = new ArrayList<GeoPoint>();
				points.add(point);

				wayIsAreaMap.put(Long.valueOf(wayId), Boolean.valueOf(isArea));
				pointMap.put(Long.valueOf(wayId), points);

			}

		} else { // not a way
			if (lastPointWasWay) {

				pointMap.put(Long.valueOf(--noWayIndex), new ArrayList<GeoPoint>());
			}

			pointMap.get(Long.valueOf(noWayIndex)).add(point);

			lastPointWasWay = false;
		}

	}

	/**
	 * Returns the central point of this track.
	 * 
	 * @return central point
	 */
	public GeoPoint getCentralGeoPoint() {
		return firstPoint;
	}

	/**
	 * Returns all point from this track.
	 * 
	 * @return Collection of all points
	 */
	public Collection<Poi> getPois() {
		pois = db.getPoisFromTrack(trackId);
		return pois;
	}

	/**
	 * Returns the track ID of the current track.
	 * 
	 * @return track ID
	 */
	public long getTrackId() {
		return trackId;
	}

	private boolean isArea(long wayId) {
		Boolean isArea;
		if (wayId <= 0)
			return false;
		if ((isArea = wayIsAreaMap.get(Long.valueOf(wayId))) != null) {
			return isArea.booleanValue();
		}

		isArea = Boolean.valueOf(db.isArea(wayId));
		wayIsAreaMap.put(Long.valueOf(wayId), isArea);
		return isArea.booleanValue();
	}
}
